package org.pidan.basic.multiThread;

/**
 * {@code @description}: Synchronized 锁
 * <p>
 * 关键字 synchronized可以保证在同一个时刻，只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作)，
 * 同时我们还应该注意到synchronized另外一个重要的作用，
 * synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到（保证可见性，完全可以替代volatile功能）
 * <p>
 * 1.修饰实例方法，作用于当前实例，进入同步代码前需要先获取实例的锁
 * 2.修饰静态方法，作用于类的Class对象，进入修饰的静态方法前需要先获取类的Class对象的锁
 * 3.修饰代码块，需要指定加锁对象(记做lockobj)，在进入同步代码块前需要先获取lockobj的锁
 * <p>
 * <p>
 * 本例为 静态方法
 * <p>
 * {@code @author}: huangyuxin
 * {@code @date}: 2023-12-13
 */
public class Synchronized {

    public static int num = 0;

    /**
     * 没有加锁时，不同线程调用，可能会出现不合设想的结果
     */
    public static void m1() {
        //i值设置大些，否则测试时，可能因为某线程执行太快，看不出效果
        for (int i = 0; i < 1000; i++) {
            num++;
        }
    }

    /**
     * 加锁后，则不会出现不合设想的结果
     */
    public static synchronized void m2() {
        //i值设置大些，否则测试时，可能因为某线程执行太快，看不出效果
        for (int i = 0; i < 1000; i++) {
            num++;
        }
    }

    public static class T1 extends Thread {

        @Override
        public void run() {
            //不加锁
//            Synchronized.m1();
            //加锁
            Synchronized.m2();
        }
    }

    public static void main(String[] args) throws InterruptedException {

        T1 t1 = new T1();
        T1 t2 = new T1();
        T1 t3 = new T1();

        t1.start();
        t2.start();
        t3.start();

        // 等待三个线程结束
        t1.join();
        t2.join();
        t3.join();

        //输出结果
        System.out.println(Synchronized.num);
    }

}
